﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Reflection;
using System.Windows.Forms;
using HML.Design;

namespace HML
{
    /// <summary>
    /// 图片裁剪控件
    /// </summary>
    [Description("图片裁剪控件")]
    [DefaultProperty("CropShape")]
    [DefaultEvent("CropperRectangleChanged")]
    [TypeConverter(typeof(ImageCropperConverter))]
    [Designer(typeof(ImageCropperDesigner))]
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(ImageCropper), "Controls.ImageCropper.Resources.ImageCropper.bmp")]
    public class ImageCropper : DpiControl, ISkinObject
    {
        #region 主题

        private SkinObjectXmlMetadata skinObjectXmlMetadata = null;
        /// <summary>
        /// 主题对象在主题文件信息
        /// </summary>
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual SkinObjectXmlMetadata SkinObjectXmlMetadata
        {
            get
            {
                if (this.skinObjectXmlMetadata == null)
                    this.skinObjectXmlMetadata = new SkinObjectXmlMetadata(Assembly.GetAssembly(typeof(ImageCropper)).GetName().Name, typeof(ImageCropper).Name);

                return this.skinObjectXmlMetadata;
            }
        }

        private SkinController skinController = null;
        /// <summary>
        /// 主题控制器
        /// </summary>
        [Description("主题控制器")]
        [Category("杂项")]
        [PropertyOrder(-360)]
        [DefaultValue(null)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinController SkinController
        {
            get { return this.skinController; }
            set
            {
                if (this.skinController == value)
                    return;

                if (this.skinController != null)
                    this.skinController.RemoveSkinObject(this);

                this.skinController = value;

                if (this.skinController != null)
                    this.skinController.AddSkinObject(this);
            }
        }

        private SkinEnabledState skinEnabled= SkinEnabledState.Auto;
        /// <summary>
        /// 主题是否启用
        /// </summary>
        [Description("主题是否启用")]
        [Category("杂项")]
        [PropertyOrder(-300)]
        [DefaultValue(SkinEnabledState.Auto)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinEnabledState SkinEnabled
        {
            get { return this.skinEnabled; }
            set
            {
                if (this.skinEnabled == value)
                    return;

                this.skinEnabled = value;
                this.OnSkinChanged();
            }
        }

        private SkinStyle skinStyle = SkinStyle.Normal;
        /// <summary>
        /// 主题风格
        /// </summary>
        [Description("主题风格")]
        [Category("杂项")]
        [PropertyOrder(-260)]
        [DefaultValue(SkinStyle.Normal)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinStyle SkinStyle
        {
            get { return this.skinStyle; }
            set
            {
                if (this.skinStyle == value)
                    return;

                this.skinStyle = value;
                this.OnSkinChanged();
            }
        }

        private StyleAppearanceObject stateAppearance;
        /// <summary>
        /// 风格外观
        /// </summary>
        [Description("风格外观")]
        [Category("杂项")]
        [PropertyOrder(-200)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public StyleAppearanceObject StyleAppearance
        {
            get
            {
                if (this.stateAppearance == null)
                    this.stateAppearance = new StyleAppearanceObject(this, null);
                return this.stateAppearance;
            }
        }

        /// <summary>
        /// 主题已更改
        /// </summary>
        public virtual void OnSkinChanged()
        {
            SkinManager.SyncSkinValueToProperty(this);
            this.Invalidate();
        }

        private ISkinObject followSkinObject = null;
        /// <summary>
        /// 主题设置跟随指定主题对象（自己的设置不再生效，提供给代码使用）
        /// </summary>
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Localizable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual ISkinObject FollowSkinObject
        {
            get { return this.followSkinObject; }
            set
            {
                if (this.followSkinObject == value)
                    return;

                this.followSkinObject = value;
                this.OnSkinChanged();
            }
        }

        public virtual bool GetSkinObjectSkinStateCore()
        {
            return SkinManager.GetSkinObjectSkinState(this.FollowSkinObject ?? this);
        }

        void ISkinObject.InitializeInvalidate()
        {
            this.InitializeElement();
            this.Invalidate();
        }

        void ISkinObject.Invalidate()
        {
            this.Invalidate();
        }

        #endregion

        #region 新增事件

        private static readonly object EventCropperRectangleChanged = new object();
        /// <summary>
        /// 剪切区域Rectangle更改事件
        /// </summary>
        [Description("剪切区域Rectangle更改事件")]
        public event EventHandler CropperRectangleChanged
        {
            add { Events.AddHandler(EventCropperRectangleChanged, value); }
            remove { Events.RemoveHandler(EventCropperRectangleChanged, value); }
        }

        #endregion

        #region 停用事件

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler PaddingChanged
        {
            add { base.PaddingChanged += value; }
            remove { base.PaddingChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TabIndexChanged
        {
            add { base.TabIndexChanged += value; }
            remove { base.TabIndexChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TabStopChanged
        {
            add { base.TabStopChanged += value; }
            remove { base.TabStopChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TextChanged
        {
            add { base.TextChanged += value; }
            remove { base.TextChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler RightToLeftChanged
        {
            add { base.RightToLeftChanged += value; }
            remove { base.RightToLeftChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ImeModeChanged
        {
            add { base.ImeModeChanged += value; }
            remove { base.ImeModeChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackgroundImageChanged
        {
            add { base.BackgroundImageChanged += value; }
            remove { base.BackgroundImageChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackgroundImageLayoutChanged
        {
            add { base.BackgroundImageLayoutChanged += value; }
            remove { base.BackgroundImageLayoutChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackColorChanged
        {
            add { base.BackColorChanged += value; }
            remove { base.BackColorChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ForeColorChanged
        {
            add { base.ForeColorChanged += value; }
            remove { base.ForeColorChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler Click
        {
            add { base.Click += value; }
            remove { base.Click -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler DoubleClick
        {
            add { base.DoubleClick += value; }
            remove { base.DoubleClick -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseClick
        {
            add { base.MouseClick += value; }
            remove { base.MouseClick -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseDoubleClick
        {
            add { base.MouseDoubleClick += value; }
            remove { base.MouseDoubleClick -= value; }
        }

        #endregion

        #region 新增属性

        private bool gripVisible = false;
        /// <summary>
        /// 是否显示透明背景网格
        /// </summary>
        [Description("是否显示透明背景网格")]
        [Category("杂项")]
        [PropertyOrder(-198)]
        [DefaultValue(false)]
        public bool GripVisible
        {
            get { return this.gripVisible; }
            set
            {
                if (this.gripVisible == value)
                    return;

                this.gripVisible = value;
                this.UpdateGripImageTmp();
                this.Invalidate();
            }
        }

        private int gripSize = 8;
        /// <summary>
        /// 透明背景网格Size
        /// </summary>
        [Description("透明背景网格Size")]
        [Category("杂项")]
        [PropertyOrder(-194)]
        [DefaultValue(8)]
        public int GripSize
        {
            get { return this.gripSize; }
            set
            {
                if (this.gripSize == value || value <= 0)
                    return;

                this.gripSize = value;
                this.UpdateGripImageTmp();
                this.Invalidate();
            }
        }

        /// <summary>
        /// 剪切区域拇指Size
        /// </summary>
        private int thumbSize = 10;
        /// <summary>
        ///  剪切区域拇指Size
        /// </summary>
        [Description("拇指Size")]
        [Category("杂项")]
        [PropertyOrder(-192)]
        [DefaultValue(10)]
        public int ThumbSize
        {
            get { return this.thumbSize; }
            set
            {
                if (this.thumbSize == value || (value <= 0))
                    return;

                this.thumbSize = value;
                this.InitializeElement();
                this.Invalidate();
            }
        }

        private ImageCropperCropShape cropperShape = ImageCropperCropShape.Rectangular;
        /// <summary>
        /// 剪切的形状
        /// </summary>
        [Description("剪切的形状")]
        [Category("杂项")]
        [PropertyOrder(-190)]
        [DefaultValue(ImageCropperCropShape.Rectangular)]
        public ImageCropperCropShape CropperShape
        {
            get { return this.cropperShape; }
            set
            {
                if (this.cropperShape == value)
                    return;

                this.cropperShape = value;
                this.UpdateCropperRectangle(this.GetCropperDefaultRectangle());
                this.Invalidate();
            }
        }

        private double? cropperAspectRatio = null;
        /// <summary>
        ///  剪切的形状比例（宽:高 null为任意尺寸）
        /// </summary>
        [Description("剪切的形状比例（宽:高 null为任意尺寸）")]
        [Category("杂项")]
        [PropertyOrder(-188)]
        [DefaultValue(null)]
        public double? CropperAspectRatio
        {
            get { return this.cropperAspectRatio; }
            set
            {
                if (this.cropperAspectRatio == value || (value.HasValue && value <= 0))
                    return;

                this.cropperAspectRatio = value;

                if (this.cropperAspectRatio.HasValue)
                {
                    this.UpdateCropperRectangle(this.GetCropperDefaultRectangle());
                    this.Invalidate();
                }
            }
        }

        private double imageScaleRatio = 100D;
        /// <summary>
        /// 图片缩放比例(1-100)
        /// </summary>
        [Description("图片缩放比例(1-100)")]
        [Category("杂项")]
        [PropertyOrder(-184)]
        [DefaultValue(100D)]
        [Browsable(false)]
        [Localizable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public double ImageScaleRatio
        {
            get { return this.imageScaleRatio; }
            set
            {
                if (value < 1)
                    value = 1;
                if (value > 100)
                    value = 100;
                if (this.imageScaleRatio == value)
                    return;

                if (this.image_tmp == null)
                {
                    this.imageScaleRatio = value;
                    this.UpdateImageTmp();
                    this.InitializeImageDefaultRectangle();
                    this.Invalidate();
                }
                else
                {
                    Point old_point = this.image_rect.Location;
                    Size old_size = new Size((int)(this.Image.Width * this.imageScaleRatio / 100f), (int)(this.Image.Height * this.imageScaleRatio / 100f));
                    Size new_size = new Size((int)(this.Image.Width * value / 100f), (int)(this.Image.Height * value / 100f));

                    int now_x = old_point.X - (new_size.Width - old_size.Width) / 2;
                    int now_y = old_point.Y - (new_size.Height - old_size.Height) / 2;
                    if (new_size.Width < this.content_rect.Width)
                    {
                        now_x = this.content_rect.X + (this.content_rect.Width - new_size.Width) / 2;
                    }
                    else if (now_x > this.content_rect.X && now_x + new_size.Width > this.content_rect.Right)
                    {
                        now_x -= Math.Min(now_x - this.content_rect.X, now_x + new_size.Width - this.content_rect.Right);
                    }
                    else if (now_x + new_size.Width < this.content_rect.Right && now_x < this.content_rect.X)
                    {
                        now_x += Math.Min(this.content_rect.Right - (now_x + new_size.Width), this.content_rect.X - now_x);
                    }

                    if (new_size.Height < this.content_rect.Height)
                    {
                        now_y = this.content_rect.Y + (this.content_rect.Height - new_size.Height) / 2;
                    }
                    else if (now_y > this.content_rect.Y && now_y + new_size.Height > this.content_rect.Bottom)
                    {
                        now_y -= Math.Min(now_y - this.content_rect.Y, now_y + new_size.Height - this.content_rect.Bottom);
                    }
                    else if (now_y + new_size.Height < this.content_rect.Bottom && now_y < this.content_rect.Y)
                    {
                        now_y += Math.Min(this.content_rect.Bottom - (now_y + new_size.Height), this.content_rect.Y - now_y);
                    }

                    this.imageScaleRatio = value;
                    this.UpdateImageTmp();
                    this.InitializeImageDefaultRectangle();
                    this.image_rect.Location = new Point(now_x, now_y);
                    this.Invalidate();
                }

            }
        }

        private Image image = null;
        /// <summary>
        /// 图片
        /// </summary>
        [Description("图片")]
        [Category("杂项")]
        [PropertyOrder(-180)]
        [DefaultValue(null)]
        [RefreshProperties(RefreshProperties.Repaint)]
        public Image Image
        {
            get { return this.image; }
            set
            {
                if (this.image == value)
                    return;

                this.image = value;
                this.UpdateImageTmp();
                this.InitializeImageDefaultRectangle();
                this.Invalidate();
            }
        }

        #endregion

        #region 重写属性

        protected override Size DefaultSize
        {
            get { return new Size(150, 150); }
        }

        protected override ImeMode DefaultImeMode
        {
            get { return ImeMode.Disable; }
        }

        #endregion

        #region 停用属性

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Padding Padding
        {
            get { return base.Padding; }
            set { base.Padding = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new int TabIndex
        {
            get { return base.TabIndex; }
            set { base.TabIndex = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new bool TabStop
        {
            get { return base.TabStop; }
            set { base.TabStop = value; }
        }

        [Bindable(false)]
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override string Text
        {
            get { return base.Text; }
            set { base.Text = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override RightToLeft RightToLeft
        {
            get { return base.RightToLeft; }
            set { base.RightToLeft = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new ImeMode ImeMode
        {
            get { return base.ImeMode; }
            set { base.ImeMode = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new Image BackgroundImage
        {
            get { return base.BackgroundImage; }
            set { base.BackgroundImage = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new ImageLayout BackgroundImageLayout
        {
            get { return base.BackgroundImageLayout; }
            set { base.BackgroundImageLayout = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Color BackColor
        {
            get { return this.StyleAppearance.BackColor; }
            set { }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Color ForeColor
        {
            get { return this.StyleAppearance.TextColor; }
            set { }
        }

        #endregion

        #region 字段

        /// <summary>
        /// 内容区rect
        /// </summary>
        private Rectangle content_rect = Rectangle.Empty;
        /// <summary>
        /// 剪切区rect
        /// </summary>
        private Rectangle cropper_rect = Rectangle.Empty;
        /// <summary>
        /// 图片区rect
        /// </summary>
        private Rectangle image_rect = Rectangle.Empty;

        /// <summary>
        /// 剪切区path
        /// </summary>
        private GraphicsPath cropper_path = new GraphicsPath();
        /// <summary>
        /// 剪切区拇指信息集合
        /// </summary>
        private Dictionary<ImageCropperDragType, Rectangle> cropper_thumbs = new Dictionary<ImageCropperDragType, Rectangle>() { { ImageCropperDragType.LeftTop, Rectangle.Empty }, { ImageCropperDragType.RightTop, Rectangle.Empty }, { ImageCropperDragType.RightBottom, Rectangle.Empty }, { ImageCropperDragType.LeftBottom, Rectangle.Empty }, { ImageCropperDragType.Top, Rectangle.Empty }, { ImageCropperDragType.Right, Rectangle.Empty }, { ImageCropperDragType.Bottom, Rectangle.Empty }, { ImageCropperDragType.Left, Rectangle.Empty } };

        /// <summary>
        /// 鼠标已按下对象
        /// </summary>
        private ImageCropperDragType mousedownobject = ImageCropperDragType.None;
        /// <summary>
        /// 鼠标按下时对象rect
        /// </summary>
        private Rectangle mousedownobjectrect = Rectangle.Empty;
        /// <summary>
        /// 鼠标按下坐标
        /// </summary>
        private Point mousedownpoint = Point.Empty;

        /// <summary>
        /// 网格图片缓存
        /// </summary>
        private Image gripimage_tmp = null;
        /// <summary>
        /// 图片缓存
        /// </summary>
        private Image image_tmp = null;

        #endregion

        public ImageCropper()
        {
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            SetStyle(ControlStyles.StandardClick, false);//自定义单击事件逻辑
            SetStyle(ControlStyles.StandardDoubleClick, false);//停用双加事件

            this.TabStop = false;
            this.InitializeElement();
            this.OnSkinChanged();
        }

        #region 重写

        protected override void OnScaleDpiChangedInitialize()
        {
            this.InitializeElement();
            this.Invalidate();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Graphics g = e.Graphics;

            //网格背景 
            if (this.GripVisible)
            {
                g.SetClip(this.content_rect);
                g.TranslateTransform(this.content_rect.X, this.content_rect.Y);

                TextureBrush grip_tb = new TextureBrush(this.gripimage_tmp, WrapMode.Tile);
                g.FillRectangle(grip_tb, new RectangleF(0, 0, this.content_rect.Width + this.content_rect.X, this.content_rect.Height + this.content_rect.Y));
                grip_tb.Dispose();

                g.ResetTransform();
                g.SetClip(this.ClientRectangle);
            }

            if (this.image_tmp != null)
            {
                //图片
                g.SetClip(this.content_rect);
                g.DrawImageUnscaled(this.image_tmp, this.image_rect.Location);
                g.SetClip(this.ClientRectangle);

                //剪切区
                if (this.CropperShape == ImageCropperCropShape.Rectangular)
                {
                    Region r = new Region(this.content_rect);
                    r.Exclude(this.cropper_rect);

                    SolidBrush mask_sb = new SolidBrush(this.StyleAppearance.MaskingColor);
                    g.FillRegion(mask_sb, r);
                    mask_sb.Dispose();

                    r.Dispose();
                }
                else
                {
                    GraphicsPath gp = new GraphicsPath();
                    gp.AddEllipse(this.cropper_rect);
                    Region r = new Region(this.content_rect);
                    r.Exclude(gp);

                    SolidBrush mask_sb = new SolidBrush(this.StyleAppearance.MaskingColor);
                    g.FillRegion(mask_sb, r);
                    mask_sb.Dispose();

                    r.Dispose();
                    gp.Dispose();
                }

                //剪切区拇指
                Pen thumb_border_pen = new Pen(this.StyleAppearance.ThumbBorderColor);
                SolidBrush thumb_back_sb = new SolidBrush(this.StyleAppearance.ThumbBackColor);
                g.SmoothingMode = SmoothingMode.AntiAlias;

                if (this.CropperShape == ImageCropperCropShape.Rectangular)
                {
                    g.FillEllipse(thumb_back_sb, this.cropper_thumbs[ImageCropperDragType.LeftTop]);
                    g.DrawEllipse(thumb_border_pen, this.cropper_thumbs[ImageCropperDragType.LeftTop]);
                    g.FillEllipse(thumb_back_sb, this.cropper_thumbs[ImageCropperDragType.RightTop]);
                    g.DrawEllipse(thumb_border_pen, this.cropper_thumbs[ImageCropperDragType.RightTop]);
                    g.FillEllipse(thumb_back_sb, this.cropper_thumbs[ImageCropperDragType.RightBottom]);
                    g.DrawEllipse(thumb_border_pen, this.cropper_thumbs[ImageCropperDragType.RightBottom]);
                    g.FillEllipse(thumb_back_sb, this.cropper_thumbs[ImageCropperDragType.LeftBottom]);
                    g.DrawEllipse(thumb_border_pen, this.cropper_thumbs[ImageCropperDragType.LeftBottom]);
                }

                g.FillEllipse(thumb_back_sb, this.cropper_thumbs[ImageCropperDragType.Top]);
                g.DrawEllipse(thumb_border_pen, this.cropper_thumbs[ImageCropperDragType.Top]);
                g.FillEllipse(thumb_back_sb, this.cropper_thumbs[ImageCropperDragType.Right]);
                g.DrawEllipse(thumb_border_pen, this.cropper_thumbs[ImageCropperDragType.Right]);
                g.FillEllipse(thumb_back_sb, this.cropper_thumbs[ImageCropperDragType.Bottom]);
                g.DrawEllipse(thumb_border_pen, this.cropper_thumbs[ImageCropperDragType.Bottom]);
                g.FillEllipse(thumb_back_sb, this.cropper_thumbs[ImageCropperDragType.Left]);
                g.DrawEllipse(thumb_border_pen, this.cropper_thumbs[ImageCropperDragType.Left]);

                g.SmoothingMode = SmoothingMode.Default;
                thumb_border_pen.Dispose();
                thumb_back_sb.Dispose();

            }

        }

        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);

            this.mousedownobject = ImageCropperDragType.None;
            this.mousedownobjectrect = Rectangle.Empty;
            this.mousedownpoint = Point.Empty;
        }

        protected override void OnEnabledChanged(EventArgs e)
        {
            base.OnEnabledChanged(e);

            if (!this.Enabled)
            {
                this.mousedownobject = ImageCropperDragType.None;
                this.mousedownobjectrect = Rectangle.Empty;
                this.mousedownpoint = Point.Empty;
                this.Invalidate();
            }
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);

            if (!this.Visible)
            {
                this.mousedownobject = ImageCropperDragType.None;
                this.mousedownobjectrect = Rectangle.Empty;
                this.mousedownpoint = Point.Empty;
                this.Invalidate();
            }
        }

        protected override void OnParentChanged(EventArgs e)
        {
            base.OnParentChanged(e);

            if (this.Parent == null)
            {
                this.mousedownobject = ImageCropperDragType.None;
                this.mousedownobjectrect = Rectangle.Empty;
                this.mousedownpoint = Point.Empty;
                this.Invalidate();
            }
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (!this.Focused)
            {
                this.Focus();
            }

            if (e.Button == MouseButtons.Left)
            {
                if (this.image_tmp != null)
                {
                    //拇指
                    foreach (KeyValuePair<ImageCropperDragType, Rectangle> item in this.cropper_thumbs)
                    {
                        if (
                            (this.CropperShape == ImageCropperCropShape.Rectangular && item.Value.Contains(e.Location)) ||
                            (this.CropperShape == ImageCropperCropShape.Circular && item.Value.Contains(e.Location) && (item.Key == ImageCropperDragType.Top || item.Key == ImageCropperDragType.Bottom || item.Key == ImageCropperDragType.Left || item.Key == ImageCropperDragType.Right))
                            )
                        {
                            this.mousedownobject = item.Key;
                            this.mousedownobjectrect = this.cropper_rect;
                            this.mousedownpoint = e.Location;
                            goto result;
                        }
                    }
                    //剪切区
                    if (this.cropper_path.IsVisible(e.Location))
                    {
                        this.mousedownobject = ImageCropperDragType.CropperMove;
                        this.mousedownobjectrect = this.cropper_rect;
                        this.mousedownpoint = e.Location;
                        goto result;
                    }
                }
            }
            else if (e.Button == MouseButtons.Right)
            {
                //图片区
                if (this.image_tmp != null && this.image_rect.Contains(e.Location))
                {
                    this.mousedownobject = ImageCropperDragType.SourceMove;
                    this.mousedownobjectrect = this.image_rect;
                    this.mousedownpoint = e.Location;
                    goto result;
                }
            }

        result:
            {

            }

            base.OnMouseDown(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            this.mousedownobject = ImageCropperDragType.None;
            this.mousedownobjectrect = Rectangle.Empty;
            this.mousedownpoint = Point.Empty;

            base.OnMouseUp(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            //拖放
            if (this.mousedownobject != ImageCropperDragType.None)
            {
                if (this.CropperShape == ImageCropperCropShape.Rectangular)
                {
                    int cropperMinSize = this.GetCropperThumbRadius() * 4;
                    Point difference = new Point(e.Location.X - this.mousedownpoint.X, e.Location.Y - this.mousedownpoint.Y);

                    switch (this.mousedownobject)
                    {
                        case ImageCropperDragType.LeftTop:
                            {
                                if (!this.CropperAspectRatio.HasValue)
                                {
                                    int current_rect_left = Math.Max(this.content_rect.X, Math.Min(this.mousedownobjectrect.Right - cropperMinSize, this.mousedownobjectrect.X + difference.X));
                                    int current_rect_top = Math.Max(this.content_rect.Y, Math.Min(this.mousedownobjectrect.Bottom - cropperMinSize, this.mousedownobjectrect.Y + difference.Y));
                                    this.UpdateCropperRectangle(new Rectangle(current_rect_left, current_rect_top, Math.Max(cropperMinSize, this.mousedownobjectrect.Right - current_rect_left), Math.Max(cropperMinSize, this.mousedownobjectrect.Bottom - current_rect_top)));
                                    this.Invalidate();
                                }
                                else
                                {
                                    double source_diagonal = Math.Sqrt(Math.Pow(this.mousedownobjectrect.Width, 2) + Math.Pow(this.mousedownobjectrect.Height, 2));
                                    double current_size_proportion = 1;
                                    if (difference.X >= 0 && difference.Y >= 0)//东南
                                    {
                                        current_size_proportion = 1 - Math.Sqrt(Math.Pow(difference.X, 2) + Math.Pow(difference.Y, 2)) / source_diagonal;
                                    }
                                    else if (difference.Y > 0 && difference.X < 0 && difference.Y > (-difference.X))//南偏西到对角线
                                    {
                                        double xy_diagonal_for_y = Math.Sqrt(Math.Pow(difference.Y, 2) + 0);
                                        double xy_diagonal_proportion = (double)(difference.Y - (-difference.X)) / (double)difference.Y;
                                        current_size_proportion = 1 - (xy_diagonal_for_y * xy_diagonal_proportion) / source_diagonal;
                                    }
                                    else if (difference.X > 0 && difference.Y < 0 && difference.X > (-difference.Y))//东偏北到对角线
                                    {
                                        double xy_diagonal_for_x = Math.Sqrt(Math.Pow(difference.X, 2) + 0);
                                        double xy_diagonal_proportion = (double)(difference.X - (-difference.Y)) / (double)difference.X;
                                        current_size_proportion = 1 - (xy_diagonal_for_x * xy_diagonal_proportion) / source_diagonal;
                                    }
                                    else if (difference.X <= 0 && difference.Y <= 0)//西北
                                    {
                                        current_size_proportion = 1 + Math.Sqrt(Math.Pow(difference.X, 2) + Math.Pow(difference.Y, 2)) / source_diagonal;
                                    }
                                    else if (difference.X < 0 && difference.Y > 0 && (-difference.X) > difference.Y)//西偏南到对角线
                                    {
                                        double xy_diagonal_for_x = Math.Sqrt(Math.Pow(difference.X, 2) + 0);
                                        double xy_diagonal_proportion = (double)((-difference.X) - difference.Y) / (double)(-difference.X);
                                        current_size_proportion = 1 + (xy_diagonal_for_x * xy_diagonal_proportion) / source_diagonal;
                                    }
                                    else if (difference.Y < 0 && difference.X > 0 && (-difference.Y) > difference.X)//北偏东到对角线
                                    {
                                        double xy_diagonal_for_y = Math.Sqrt(Math.Pow(difference.Y, 2) + 0);
                                        double xy_diagonal_proportion = (double)((-difference.Y) - difference.X) / (double)(-difference.Y);
                                        current_size_proportion = 1 + (xy_diagonal_for_y * xy_diagonal_proportion) / source_diagonal;
                                    }

                                    int current_size_w = Math.Max(cropperMinSize, (int)(this.mousedownobjectrect.Width * current_size_proportion));
                                    int current_size_h = Math.Max(cropperMinSize, (int)(this.mousedownobjectrect.Height * current_size_proportion));

                                    int current_minsize_w = (int)(cropperMinSize * this.CropperAspectRatio.Value);
                                    if (current_size_w < current_minsize_w)
                                    {
                                        current_size_w = current_minsize_w;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio.Value);
                                    }
                                    int current_minsize_h = (int)(cropperMinSize / this.CropperAspectRatio.Value);
                                    if (current_size_h < current_minsize_h)
                                    {
                                        current_size_h = current_minsize_h;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio.Value);
                                    }

                                    int current_size_x_offset = (this.mousedownobjectrect.Right - current_size_w) - this.content_rect.X;
                                    if (current_size_x_offset < 0)
                                    {
                                        current_size_w += current_size_x_offset;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio);
                                    }
                                    int current_size_y_offset = Math.Min(0, (this.mousedownobjectrect.Bottom - current_size_h) - this.content_rect.X);
                                    if (current_size_y_offset < 0)
                                    {
                                        current_size_h += current_size_y_offset;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio);
                                    }

                                    this.UpdateCropperRectangle(new Rectangle(this.mousedownobjectrect.Right - current_size_w, this.mousedownobjectrect.Bottom - current_size_h, current_size_w, current_size_h));
                                    this.Invalidate();
                                }

                                break;
                            }
                        case ImageCropperDragType.RightTop:
                            {
                                if (!this.CropperAspectRatio.HasValue)
                                {
                                    int current_rect_right = Math.Min(this.content_rect.Right, Math.Max(this.mousedownobjectrect.X + cropperMinSize, this.mousedownobjectrect.Right + difference.X));
                                    int current_rect_top = Math.Max(this.content_rect.Y, Math.Min(this.mousedownobjectrect.Bottom - cropperMinSize, this.mousedownobjectrect.Y + difference.Y));
                                    this.UpdateCropperRectangle(new Rectangle(this.mousedownobjectrect.X, current_rect_top, Math.Max(cropperMinSize, current_rect_right - this.mousedownobjectrect.X), Math.Max(cropperMinSize, this.mousedownobjectrect.Bottom - current_rect_top)));
                                    this.Invalidate();
                                }
                                else
                                {
                                    double source_diagonal = Math.Sqrt(Math.Pow(this.mousedownobjectrect.Width, 2) + Math.Pow(this.mousedownobjectrect.Height, 2));
                                    double current_size_proportion = 1;
                                    if (difference.X <= 0 && difference.Y >= 0)//西南
                                    {
                                        current_size_proportion = 1 - Math.Sqrt(Math.Pow(difference.X, 2) + Math.Pow(difference.Y, 2)) / source_diagonal;
                                    }
                                    else if (difference.X < 0 && difference.Y < 0 && (-difference.X) > (-difference.Y))//西偏北到对角线
                                    {
                                        double xy_diagonal_for_x = Math.Sqrt(Math.Pow(difference.X, 2) + 0);
                                        double xy_diagonal_proportion = (double)((-difference.X) - (-difference.Y)) / (double)(-difference.X);
                                        current_size_proportion = 1 - (xy_diagonal_for_x * xy_diagonal_proportion) / source_diagonal;
                                    }
                                    else if (difference.Y > 0 && difference.X > 0 && difference.Y > difference.X)//南偏东到对角线
                                    {
                                        double xy_diagonal_for_y = Math.Sqrt(Math.Pow(difference.Y, 2) + 0);
                                        double xy_diagonal_proportion = (double)(difference.Y - difference.X) / (double)difference.Y;
                                        current_size_proportion = 1 - (xy_diagonal_for_y * xy_diagonal_proportion) / source_diagonal;
                                    }
                                    else if (difference.X > 0 && difference.Y < 0)//东北
                                    {
                                        current_size_proportion = 1 + Math.Sqrt(Math.Pow(difference.X, 2) + Math.Pow(difference.Y, 2)) / source_diagonal;
                                    }
                                    else if (difference.Y < 0 && difference.X < 0 && (-difference.Y) > (-difference.X))//北偏西到对角线
                                    {
                                        double xy_diagonal_for_y = Math.Sqrt(Math.Pow(difference.Y, 2) + 0);
                                        double xy_diagonal_proportion = (double)((-difference.Y) - (-difference.X)) / (double)(-difference.Y);
                                        current_size_proportion = 1 + (xy_diagonal_for_y * xy_diagonal_proportion) / source_diagonal;
                                    }
                                    else if (difference.X > 0 && difference.Y > 0 && difference.X > difference.Y)//东偏南到对角线
                                    {
                                        double xy_diagonal_for_x = Math.Sqrt(Math.Pow(difference.X, 2) + 0);
                                        double xy_diagonal_proportion = (double)(difference.X - difference.Y) / (double)difference.X;
                                        current_size_proportion = 1 + (xy_diagonal_for_x * xy_diagonal_proportion) / source_diagonal;
                                    }

                                    int current_size_w = Math.Max(cropperMinSize, (int)(this.mousedownobjectrect.Width * current_size_proportion));
                                    int current_size_h = Math.Max(cropperMinSize, (int)(this.mousedownobjectrect.Height * current_size_proportion));

                                    int current_maxsize_w = this.content_rect.Right - this.mousedownobjectrect.X;
                                    if (current_size_w > current_maxsize_w)
                                    {
                                        current_size_w = current_maxsize_w;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio);
                                    }
                                    int current_minsize_w = (int)(cropperMinSize * this.CropperAspectRatio.Value);
                                    if (current_size_w < current_minsize_w)
                                    {
                                        current_size_w = current_minsize_w;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio.Value);
                                    }
                                    int current_maxsize_h = this.mousedownobjectrect.Bottom - this.content_rect.Y;
                                    if (current_size_h > current_maxsize_h)
                                    {
                                        current_size_h = current_maxsize_h;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio);
                                    }
                                    int current_minsize_h = (int)(cropperMinSize / this.CropperAspectRatio.Value);
                                    if (current_size_h < current_minsize_h)
                                    {
                                        current_size_h = current_minsize_h;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio.Value);
                                    }

                                    int current_size_y_offset = Math.Min(0, (this.mousedownobjectrect.Bottom - current_size_h) - this.content_rect.X);
                                    if (current_size_y_offset < 0)
                                    {
                                        current_size_h += current_size_y_offset;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio);
                                    }

                                    this.UpdateCropperRectangle(new Rectangle(this.mousedownobjectrect.X, this.mousedownobjectrect.Bottom - current_size_h, current_size_w, current_size_h));
                                    this.Invalidate();
                                }

                                break;
                            }
                        case ImageCropperDragType.RightBottom:
                            {
                                if (!this.CropperAspectRatio.HasValue)
                                {
                                    int current_rect_right = Math.Min(this.content_rect.Right, Math.Max(this.mousedownobjectrect.X + cropperMinSize, this.mousedownobjectrect.Right + difference.X));
                                    int current_rect_bottom = Math.Min(this.content_rect.Bottom, Math.Max(this.mousedownobjectrect.Y + cropperMinSize, this.mousedownobjectrect.Bottom + difference.Y));
                                    this.UpdateCropperRectangle(new Rectangle(this.mousedownobjectrect.X, this.mousedownobjectrect.Y, Math.Max(cropperMinSize, current_rect_right - this.mousedownobjectrect.X), Math.Max(cropperMinSize, current_rect_bottom - this.mousedownobjectrect.Y)));
                                    this.Invalidate();
                                }
                                else
                                {
                                    double source_diagonal = Math.Sqrt(Math.Pow(this.mousedownobjectrect.Width, 2) + Math.Pow(this.mousedownobjectrect.Height, 2));
                                    double current_size_proportion = 1;
                                    if (difference.X <= 0 && difference.Y <= 0)//西北
                                    {
                                        current_size_proportion = 1 - Math.Sqrt(Math.Pow(difference.X, 2) + Math.Pow(difference.Y, 2)) / source_diagonal;
                                    }
                                    else if (difference.Y < 0 && difference.X > 0 && (-difference.Y) > difference.X)//北偏东到对角线
                                    {
                                        double xy_diagonal_for_y = Math.Sqrt(Math.Pow(difference.Y, 2) + 0);
                                        double xy_diagonal_proportion = (double)((-difference.Y) - difference.X) / (double)(-difference.Y);
                                        current_size_proportion = 1 - (xy_diagonal_for_y * xy_diagonal_proportion) / source_diagonal;
                                    }
                                    else if (difference.X < 0 && difference.Y > 0 && (-difference.X) > difference.Y)//西偏南到对角线
                                    {
                                        double xy_diagonal_for_x = Math.Sqrt(Math.Pow(difference.X, 2) + 0);
                                        double xy_diagonal_proportion = (double)((-difference.X) - difference.Y) / (double)(-difference.X);
                                        current_size_proportion = 1 - (xy_diagonal_for_x * xy_diagonal_proportion) / source_diagonal;
                                    }
                                    else if (difference.X > 0 && difference.Y > 0)//东南
                                    {
                                        current_size_proportion = 1 + Math.Sqrt(Math.Pow(difference.X, 2) + Math.Pow(difference.Y, 2)) / source_diagonal;
                                    }
                                    else if (difference.X > 0 && difference.Y < 0 && difference.X > (-difference.Y))//东偏北到对角线
                                    {
                                        double xy_diagonal_for_x = Math.Sqrt(Math.Pow(difference.X, 2) + 0);
                                        double xy_diagonal_proportion = (double)(difference.X - (-difference.Y)) / (double)difference.X;
                                        current_size_proportion = 1 + (xy_diagonal_for_x * xy_diagonal_proportion) / source_diagonal;
                                    }
                                    else if (difference.Y > 0 && difference.X < 0 && difference.Y > (-difference.X))//南偏西到对角线
                                    {
                                        double xy_diagonal_for_y = Math.Sqrt(Math.Pow(difference.Y, 2) + 0);
                                        double xy_diagonal_proportion = (double)(difference.Y - (-difference.X)) / (double)difference.Y;
                                        current_size_proportion = 1 + (xy_diagonal_for_y * xy_diagonal_proportion) / source_diagonal;
                                    }

                                    int current_size_w = Math.Max(cropperMinSize, (int)(this.mousedownobjectrect.Width * current_size_proportion));
                                    int current_size_h = Math.Max(cropperMinSize, (int)(this.mousedownobjectrect.Height * current_size_proportion));

                                    int current_maxsize_w = this.content_rect.Right - this.mousedownobjectrect.X;
                                    if (current_size_w > current_maxsize_w)
                                    {
                                        current_size_w = current_maxsize_w;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio);
                                    }
                                    int current_minsize_w = (int)(cropperMinSize * this.CropperAspectRatio.Value);
                                    if (current_size_w < current_minsize_w)
                                    {
                                        current_size_w = current_minsize_w;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio.Value);
                                    }
                                    int current_maxsize_h = this.content_rect.Bottom - this.mousedownobjectrect.Y;
                                    if (current_size_h > current_maxsize_h)
                                    {
                                        current_size_h = current_maxsize_h;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio);
                                    }
                                    int current_minsize_h = (int)(cropperMinSize / this.CropperAspectRatio.Value);
                                    if (current_size_h < current_minsize_h)
                                    {
                                        current_size_h = current_minsize_h;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio.Value);
                                    }

                                    this.UpdateCropperRectangle(new Rectangle(this.mousedownobjectrect.X, this.mousedownobjectrect.Y, current_size_w, current_size_h));
                                    this.Invalidate();
                                }

                                break;
                            }
                        case ImageCropperDragType.LeftBottom:
                            {
                                if (!this.CropperAspectRatio.HasValue)
                                {
                                    int current_rect_left = Math.Max(this.content_rect.X, Math.Min(this.mousedownobjectrect.Right - cropperMinSize, this.mousedownobjectrect.X + difference.X));
                                    int current_rect_bottom = Math.Min(this.content_rect.Bottom, Math.Max(this.mousedownobjectrect.Y + cropperMinSize, this.mousedownobjectrect.Bottom + difference.Y));
                                    this.UpdateCropperRectangle(new Rectangle(current_rect_left, this.mousedownobjectrect.Y, Math.Max(cropperMinSize, this.mousedownobjectrect.Right - current_rect_left), Math.Max(cropperMinSize, current_rect_bottom - this.mousedownobjectrect.Y)));
                                    this.Invalidate();
                                }
                                else
                                {
                                    double source_diagonal = Math.Sqrt(Math.Pow(this.mousedownobjectrect.Width, 2) + Math.Pow(this.mousedownobjectrect.Height, 2));
                                    double current_size_proportion = 1;
                                    if (difference.X >= 0 && difference.Y <= 0)//东北
                                    {
                                        current_size_proportion = 1 - Math.Sqrt(Math.Pow(difference.X, 2) + Math.Pow(difference.Y, 2)) / source_diagonal;
                                    }
                                    else if (difference.X > 0 && difference.Y > 0 && difference.X > difference.Y)//东偏南到对角线
                                    {
                                        double xy_diagonal_for_x = Math.Sqrt(Math.Pow(difference.X, 2) + 0);
                                        double xy_diagonal_proportion = (double)(difference.X - difference.Y) / (double)difference.X;
                                        current_size_proportion = 1 - (xy_diagonal_for_x * xy_diagonal_proportion) / source_diagonal;
                                    }
                                    else if (difference.Y < 0 && difference.X < 0 && (-difference.Y) > (-difference.X))//北偏西到对角线
                                    {
                                        double xy_diagonal_for_y = Math.Sqrt(Math.Pow(difference.Y, 2) + 0);
                                        double xy_diagonal_proportion = (double)((-difference.Y) - (-difference.X)) / (double)(-difference.Y);
                                        current_size_proportion = 1 - (xy_diagonal_for_y * xy_diagonal_proportion) / source_diagonal;
                                    }
                                    else if (difference.X <= 0 && difference.Y >= 0)//西南
                                    {
                                        current_size_proportion = 1 + Math.Sqrt(Math.Pow(difference.X, 2) + Math.Pow(difference.Y, 2)) / source_diagonal;
                                    }
                                    else if (difference.Y > 0 && difference.X > 0 && difference.Y > difference.X)//南偏东到对角线
                                    {
                                        double xy_diagonal_for_y = Math.Sqrt(Math.Pow(difference.Y, 2) + 0);
                                        double xy_diagonal_proportion = (double)(difference.Y - difference.X) / (double)difference.Y;
                                        current_size_proportion = 1 + (xy_diagonal_for_y * xy_diagonal_proportion) / source_diagonal;
                                    }
                                    else if (difference.X < 0 && difference.Y < 0 && (-difference.X) > (-difference.Y))//西偏北到对角线
                                    {
                                        double xy_diagonal_for_x = Math.Sqrt(Math.Pow(difference.X, 2) + 0);
                                        double xy_diagonal_proportion = (double)((-difference.X) - (-difference.Y)) / (double)(-difference.X);
                                        current_size_proportion = 1 + (xy_diagonal_for_x * xy_diagonal_proportion) / source_diagonal;
                                    }

                                    int current_size_w = Math.Max(cropperMinSize, (int)(this.mousedownobjectrect.Width * current_size_proportion));
                                    int current_size_h = Math.Max(cropperMinSize, (int)(this.mousedownobjectrect.Height * current_size_proportion));

                                    int current_maxsize_w = this.mousedownobjectrect.Right - this.content_rect.X;
                                    if (current_size_w > current_maxsize_w)
                                    {
                                        current_size_w = current_maxsize_w;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio);
                                    }
                                    int current_minsize_w = (int)(cropperMinSize * this.CropperAspectRatio.Value);
                                    if (current_size_w < current_minsize_w)
                                    {
                                        current_size_w = current_minsize_w;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio.Value);
                                    }
                                    int current_maxsize_h = this.content_rect.Bottom - this.mousedownobjectrect.Y;
                                    if (current_size_h > current_maxsize_h)
                                    {
                                        current_size_h = current_maxsize_h;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio);
                                    }
                                    int current_minsize_h = (int)(cropperMinSize / this.CropperAspectRatio.Value);
                                    if (current_size_h < current_minsize_h)
                                    {
                                        current_size_h = current_minsize_h;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio.Value);
                                    }

                                    int current_size_x_offset = (this.mousedownobjectrect.Right - current_size_w) - this.content_rect.X;
                                    if (current_size_x_offset < 0)
                                    {
                                        current_size_w += current_size_x_offset;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio);
                                    }

                                    this.UpdateCropperRectangle(new Rectangle(this.mousedownobjectrect.Right - current_size_w, this.mousedownobjectrect.Y, current_size_w, current_size_h));
                                    this.Invalidate();
                                }

                                break;
                            }
                        case ImageCropperDragType.Top:
                            {
                                if (!this.CropperAspectRatio.HasValue)
                                {
                                    int current_rect_top = Math.Max(this.content_rect.Y, Math.Min(this.mousedownobjectrect.Bottom - cropperMinSize, this.mousedownobjectrect.Y + difference.Y));
                                    this.UpdateCropperRectangle(new Rectangle(this.mousedownobjectrect.X, current_rect_top, this.mousedownobjectrect.Width, Math.Max(cropperMinSize, this.mousedownobjectrect.Bottom - current_rect_top)));
                                    this.Invalidate();
                                }
                                else
                                {
                                    int current_size_h = Math.Max(cropperMinSize, this.mousedownobjectrect.Height - difference.Y);
                                    int current_size_w = Math.Max(cropperMinSize, (int)(current_size_h * this.CropperAspectRatio));
                                    int current_size_center = this.mousedownobjectrect.X + this.mousedownobjectrect.Width / 2;

                                    int current_maxsize_w = Math.Min((this.content_rect.Right - current_size_center), (current_size_center - this.content_rect.X)) * 2;
                                    if (current_size_w > current_maxsize_w)
                                    {
                                        current_size_w = current_maxsize_w;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio.Value);
                                    }
                                    int current_maxsize_h = this.mousedownobjectrect.Bottom - this.content_rect.Y;
                                    if (current_size_h > current_maxsize_h)
                                    {
                                        current_size_h = current_maxsize_h;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio);
                                    }
                                    int current_minsize_h = (int)(cropperMinSize / this.CropperAspectRatio.Value);
                                    if (current_size_h < current_minsize_h)
                                    {
                                        current_size_h = current_minsize_h;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio.Value);
                                    }

                                    this.UpdateCropperRectangle(new Rectangle(current_size_center - current_size_w / 2, this.mousedownobjectrect.Bottom - current_size_h, current_size_w, current_size_h));
                                    this.Invalidate();
                                }

                                break;
                            }
                        case ImageCropperDragType.Right:
                            {
                                if (!this.CropperAspectRatio.HasValue)
                                {
                                    int current_rect_right = Math.Min(this.content_rect.Right, Math.Max(this.mousedownobjectrect.X + cropperMinSize, this.mousedownobjectrect.Right + difference.X));
                                    this.UpdateCropperRectangle(new Rectangle(this.mousedownobjectrect.X, this.mousedownobjectrect.Y, Math.Max(cropperMinSize, current_rect_right - this.mousedownobjectrect.X), this.mousedownobjectrect.Height));
                                    this.Invalidate();
                                }
                                else
                                {
                                    int current_size_w = Math.Max(cropperMinSize, this.mousedownobjectrect.Width + difference.X);
                                    int current_size_h = Math.Max(cropperMinSize, (int)(current_size_w / this.CropperAspectRatio));
                                    int current_size_center = this.mousedownobjectrect.Y + this.mousedownobjectrect.Height / 2;

                                    int current_maxsize_h = Math.Min((this.content_rect.Bottom - current_size_center), (current_size_center - this.content_rect.Y)) * 2;
                                    if (current_size_h > current_maxsize_h)
                                    {
                                        current_size_h = current_maxsize_h;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio);
                                    }
                                    int current_maxsize_w = this.content_rect.Right - this.mousedownobjectrect.X;
                                    if (current_size_w > current_maxsize_w)
                                    {
                                        current_size_w = current_maxsize_w;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio);
                                    }
                                    int current_minsize_w = (int)(cropperMinSize * this.CropperAspectRatio.Value);
                                    if (current_size_w < current_minsize_w)
                                    {
                                        current_size_w = current_minsize_w;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio.Value);
                                    }

                                    this.UpdateCropperRectangle(new Rectangle(this.mousedownobjectrect.X, current_size_center - current_size_h / 2, current_size_w, current_size_h));
                                    this.Invalidate();
                                }

                                break;
                            }
                        case ImageCropperDragType.Bottom:
                            {
                                if (!this.CropperAspectRatio.HasValue)
                                {
                                    int current_rect_bottom = Math.Min(this.content_rect.Bottom, Math.Max(this.mousedownobjectrect.Y + cropperMinSize, this.mousedownobjectrect.Bottom + difference.Y));
                                    this.UpdateCropperRectangle(new Rectangle(this.mousedownobjectrect.X, this.mousedownobjectrect.Y, this.mousedownobjectrect.Width, Math.Max(cropperMinSize, current_rect_bottom - this.mousedownobjectrect.Y)));
                                    this.Invalidate();
                                }
                                else
                                {
                                    int current_size_h = Math.Max(cropperMinSize, this.mousedownobjectrect.Height + difference.Y);
                                    int current_size_w = Math.Max(cropperMinSize, (int)(current_size_h * this.CropperAspectRatio));
                                    int current_size_center = this.mousedownobjectrect.X + this.mousedownobjectrect.Width / 2;

                                    int current_maxsize_w = Math.Min((this.content_rect.Right - current_size_center), (current_size_center - this.content_rect.X)) * 2;
                                    if (current_size_w > current_maxsize_w)
                                    {
                                        current_size_w = current_maxsize_w;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio);
                                    }
                                    int current_maxsize_h = this.content_rect.Bottom - this.mousedownobjectrect.Y;
                                    if (current_size_h > current_maxsize_h)
                                    {
                                        current_size_h = current_maxsize_h;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio);
                                    }
                                    int current_minsize_h = (int)(cropperMinSize / this.CropperAspectRatio.Value);
                                    if (current_size_h < current_minsize_h)
                                    {
                                        current_size_h = current_minsize_h;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio.Value);
                                    }

                                    this.UpdateCropperRectangle(new Rectangle(current_size_center - current_size_w / 2, this.mousedownobjectrect.Y, current_size_w, current_size_h));
                                    this.Invalidate();
                                }

                                break;
                            }
                        case ImageCropperDragType.Left:
                            {
                                if (!this.CropperAspectRatio.HasValue)
                                {
                                    int current_rect_left = Math.Max(this.content_rect.X, Math.Min(this.mousedownobjectrect.Right - cropperMinSize, this.mousedownobjectrect.X + difference.X));
                                    this.UpdateCropperRectangle(new Rectangle(current_rect_left, this.mousedownobjectrect.Y, Math.Max(cropperMinSize, this.mousedownobjectrect.Right - current_rect_left), this.mousedownobjectrect.Height));
                                    this.Invalidate();
                                }
                                else
                                {
                                    int current_size_w = Math.Max(cropperMinSize, this.mousedownobjectrect.Width - difference.X);
                                    int current_size_h = Math.Max(cropperMinSize, (int)(current_size_w / this.CropperAspectRatio));
                                    int current_size_center = this.mousedownobjectrect.Y + this.mousedownobjectrect.Height / 2;

                                    int current_maxsize_h = Math.Min((this.content_rect.Bottom - current_size_center), (current_size_center - this.content_rect.Y)) * 2;
                                    if (current_size_h > current_maxsize_h)
                                    {
                                        current_size_h = current_maxsize_h;
                                        current_size_w = (int)(current_size_h * this.CropperAspectRatio);
                                    }
                                    int current_maxsize_w = this.mousedownobjectrect.Right - this.content_rect.X;
                                    if (current_size_w > current_maxsize_w)
                                    {
                                        current_size_w = current_maxsize_w;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio);
                                    }
                                    int current_minsize_w = (int)(cropperMinSize * this.CropperAspectRatio.Value);
                                    if (current_size_w < current_minsize_w)
                                    {
                                        current_size_w = current_minsize_w;
                                        current_size_h = (int)(current_size_w / this.CropperAspectRatio.Value);
                                    }

                                    this.UpdateCropperRectangle(new Rectangle(this.mousedownobjectrect.Right - current_size_w, current_size_center - current_size_h / 2, current_size_w, current_size_h));
                                    this.Invalidate();
                                }

                                break;
                            }
                        case ImageCropperDragType.CropperMove:
                            {
                                int x = Math.Min(this.content_rect.Right - this.mousedownobjectrect.Width, Math.Max(this.content_rect.X, this.mousedownobjectrect.X + difference.X));
                                int y = Math.Min(this.content_rect.Bottom - this.mousedownobjectrect.Height, Math.Max(this.content_rect.Y, this.mousedownobjectrect.Y + difference.Y));
                                Rectangle tmp = new Rectangle(x, y, this.mousedownobjectrect.Width, this.mousedownobjectrect.Height);
                                this.UpdateCropperRectangle(tmp);
                                this.Invalidate();

                                break;
                            }
                        case ImageCropperDragType.SourceMove:
                            {
                                int now_x = this.mousedownobjectrect.Location.X + difference.X;
                                int now_y = this.mousedownobjectrect.Location.Y + difference.Y;

                                if (this.mousedownobjectrect.Width < this.content_rect.Width)
                                {
                                    now_x = this.content_rect.X + (this.content_rect.Width - this.mousedownobjectrect.Width) / 2;
                                }
                                else if (now_x > this.content_rect.X && now_x + this.mousedownobjectrect.Width > this.content_rect.Right)
                                {
                                    now_x -= Math.Min(now_x - this.content_rect.X, now_x + this.mousedownobjectrect.Width - this.content_rect.Right);
                                }
                                else if (now_x + this.mousedownobjectrect.Width < this.content_rect.Right && now_x < this.content_rect.X)
                                {
                                    now_x += Math.Min(this.content_rect.Right - (now_x + this.mousedownobjectrect.Width), this.content_rect.X - now_x);
                                }

                                if (this.mousedownobjectrect.Height < this.content_rect.Height)
                                {
                                    now_y = this.content_rect.Y + (this.content_rect.Height - this.mousedownobjectrect.Height) / 2;
                                }
                                else if (now_y > this.content_rect.Y && now_y + this.mousedownobjectrect.Height > this.content_rect.Bottom)
                                {
                                    now_y -= Math.Min(now_y - this.content_rect.Y, now_y + this.mousedownobjectrect.Height - this.content_rect.Bottom);
                                }
                                else if (now_y + this.mousedownobjectrect.Height < this.content_rect.Bottom && now_y < this.content_rect.Y)
                                {
                                    now_y += Math.Min(this.content_rect.Bottom - (now_y + this.mousedownobjectrect.Height), this.content_rect.Y - now_y);
                                }

                                this.image_rect.Location = new Point(now_x, now_y);
                                this.Invalidate();

                                break;
                            }
                    }
                }
                else
                {
                    int cropperMinSize = this.GetCropperThumbRadius() * 3;
                    Point difference = new Point(e.Location.X - this.mousedownpoint.X, e.Location.Y - this.mousedownpoint.Y);

                    switch (this.mousedownobject)
                    {
                        case ImageCropperDragType.Top:
                            {
                                int current_size_center = this.mousedownobjectrect.X + this.mousedownobjectrect.Width / 2;
                                int current_size = Math.Max(cropperMinSize, Math.Min(this.mousedownobjectrect.Height - difference.Y, this.mousedownobjectrect.Bottom - this.content_rect.Y));
                                current_size = Math.Min(current_size, Math.Min((this.content_rect.Right - current_size_center), (current_size_center - this.content_rect.X)) * 2);

                                this.UpdateCropperRectangle(new Rectangle(current_size_center - current_size / 2, this.mousedownobjectrect.Bottom - current_size, current_size, current_size));
                                this.Invalidate();

                                break;
                            }
                        case ImageCropperDragType.Right:
                            {
                                int current_size_center = this.mousedownobjectrect.Y + this.mousedownobjectrect.Height / 2;
                                int current_size = Math.Max(cropperMinSize, Math.Min(this.mousedownobjectrect.Width + difference.X, this.content_rect.Right - this.mousedownobjectrect.X));
                                current_size = Math.Min(current_size, Math.Min((this.content_rect.Bottom - current_size_center), (current_size_center - this.content_rect.Y)) * 2);

                                this.UpdateCropperRectangle(new Rectangle(this.mousedownobjectrect.X, current_size_center - current_size / 2, current_size, current_size));
                                this.Invalidate();

                                break;
                            }
                        case ImageCropperDragType.Bottom:
                            {
                                int current_size_center = this.mousedownobjectrect.X + this.mousedownobjectrect.Width / 2;
                                int current_size = Math.Max(cropperMinSize, Math.Min(this.mousedownobjectrect.Height + difference.Y, this.content_rect.Bottom - this.mousedownobjectrect.Y));
                                current_size = Math.Min(current_size, Math.Min((this.content_rect.Right - current_size_center), (current_size_center - this.content_rect.X)) * 2);

                                this.UpdateCropperRectangle(new Rectangle(current_size_center - current_size / 2, this.mousedownobjectrect.Y, current_size, current_size));
                                this.Invalidate();

                                break;
                            }
                        case ImageCropperDragType.Left:
                            {
                                int current_size_center = this.mousedownobjectrect.Y + this.mousedownobjectrect.Height / 2;
                                int current_size = Math.Max(cropperMinSize, Math.Min(this.mousedownobjectrect.Width - difference.X, this.mousedownobjectrect.Right - this.content_rect.X));
                                current_size = Math.Min(current_size, Math.Min((this.content_rect.Bottom - current_size_center), (current_size_center - this.content_rect.Y)) * 2);

                                this.UpdateCropperRectangle(new Rectangle(this.mousedownobjectrect.Right - current_size, current_size_center - current_size / 2, current_size, current_size));
                                this.Invalidate();

                                break;
                            }
                        case ImageCropperDragType.CropperMove:
                            {
                                int x = Math.Min(this.content_rect.Right - this.mousedownobjectrect.Width, Math.Max(this.content_rect.X, this.mousedownobjectrect.X + difference.X));
                                int y = Math.Min(this.content_rect.Bottom - this.mousedownobjectrect.Height, Math.Max(this.content_rect.Y, this.mousedownobjectrect.Y + difference.Y));
                                Rectangle tmp = new Rectangle(x, y, this.mousedownobjectrect.Width, this.mousedownobjectrect.Height);
                                this.UpdateCropperRectangle(tmp);
                                this.Invalidate();

                                break;
                            }
                        case ImageCropperDragType.SourceMove:
                            {
                                int now_x = this.mousedownobjectrect.Location.X + difference.X;
                                int now_y = this.mousedownobjectrect.Location.Y + difference.Y;

                                if (this.mousedownobjectrect.Width < this.content_rect.Width)
                                {
                                    now_x = this.content_rect.X + (this.content_rect.Width - this.mousedownobjectrect.Width) / 2;
                                }
                                else if (now_x > this.content_rect.X && now_x + this.mousedownobjectrect.Width > this.content_rect.Right)
                                {
                                    now_x -= Math.Min(now_x - this.content_rect.X, now_x + this.mousedownobjectrect.Width - this.content_rect.Right);
                                }
                                else if (now_x + this.mousedownobjectrect.Width < this.content_rect.Right && now_x < this.content_rect.X)
                                {
                                    now_x += Math.Min(this.content_rect.Right - (now_x + this.mousedownobjectrect.Width), this.content_rect.X - now_x);
                                }

                                if (this.mousedownobjectrect.Height < this.content_rect.Height)
                                {
                                    now_y = this.content_rect.Y + (this.content_rect.Height - this.mousedownobjectrect.Height) / 2;
                                }
                                else if (now_y > this.content_rect.Y && now_y + this.mousedownobjectrect.Height > this.content_rect.Bottom)
                                {
                                    now_y -= Math.Min(now_y - this.content_rect.Y, now_y + this.mousedownobjectrect.Height - this.content_rect.Bottom);
                                }
                                else if (now_y + this.mousedownobjectrect.Height < this.content_rect.Bottom && now_y < this.content_rect.Y)
                                {
                                    now_y += Math.Min(this.content_rect.Bottom - (now_y + this.mousedownobjectrect.Height), this.content_rect.Y - now_y);
                                }

                                this.image_rect.Location = new Point(now_x, now_y);
                                this.Invalidate();

                                break;
                            }
                    }
                }
            }

            //光标
            if (this.image_tmp != null)
            {
                bool isfind = false;
                foreach (KeyValuePair<ImageCropperDragType, Rectangle> item in this.cropper_thumbs)
                {
                    if (item.Value.Contains(e.Location))
                    {
                        if ((item.Key == ImageCropperDragType.LeftTop || item.Key == ImageCropperDragType.RightBottom) && this.CropperShape == ImageCropperCropShape.Rectangular)
                        {
                            if (this.Cursor != Cursors.SizeNWSE)
                            {
                                this.Cursor = Cursors.SizeNWSE;
                            }
                            isfind = true;
                            break;
                        }
                        else if ((item.Key == ImageCropperDragType.RightTop || item.Key == ImageCropperDragType.LeftBottom) && this.CropperShape == ImageCropperCropShape.Rectangular)
                        {
                            if (this.Cursor != Cursors.SizeNESW)
                            {
                                this.Cursor = Cursors.SizeNESW;
                            }
                            isfind = true;
                            break;
                        }
                        else if (item.Key == ImageCropperDragType.Top || item.Key == ImageCropperDragType.Bottom)
                        {
                            if (this.Cursor != Cursors.SizeNS)
                            {
                                this.Cursor = Cursors.SizeNS;
                            }
                            isfind = true;
                            break;
                        }
                        else if (item.Key == ImageCropperDragType.Left || item.Key == ImageCropperDragType.Right)
                        {
                            if (this.Cursor != Cursors.SizeWE)
                            {
                                this.Cursor = Cursors.SizeWE;
                            }
                            isfind = true;
                            break;
                        }
                    }
                }
                if (!isfind && this.Cursor != Cursors.Default)
                {
                    this.Cursor = Cursors.Default;
                }
            }

        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);

            this.InitializeElement();
            this.Invalidate();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.gripimage_tmp != null)
                    this.gripimage_tmp.Dispose();
                if (this.image_tmp != null)
                    this.image_tmp.Dispose();
                if (this.cropper_path != null)
                    this.cropper_path.Dispose();
            }
            base.Dispose(disposing);
        }

        #endregion

        #region 虚方法

        protected virtual void OnCropperRectangleChanged(EventArgs e)
        {
            EventHandler handler = Events[EventCropperRectangleChanged] as EventHandler;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        #endregion

        #region 公开方法

        /// <summary>
        /// 重置信息
        /// </summary>
        public void ResetControl()
        {
            this.InitializeElement();
            this.Invalidate();
        }

        /// <summary>
        /// 剪切当前选中区域图片
        /// </summary>
        /// <param name="scaleCropper">是否按缩放后大小进行剪切</param>
        /// <returns></returns>
        public Bitmap CropperSourceImage(bool scaleCropper)
        {
            if (this.image_tmp == null)
                return null;

            Image source_image = this.image_tmp;
            Rectangle source_image_rect = this.image_rect;
            Rectangle source_cropper_rect = this.cropper_rect;
            if (!scaleCropper)
            {
                source_image = this.Image;
                source_image_rect = this.ConvertRectangle(this.image_rect);
                source_cropper_rect = this.ConvertRectangle(this.cropper_rect);
            }

            Rectangle source_src_rect = new Rectangle(source_image_rect.X, source_image_rect.Y, source_image_rect.Width, source_image_rect.Height);
            source_src_rect.Intersect(source_cropper_rect);
            source_src_rect.Location = new Point(source_src_rect.Location.X - source_image_rect.Location.X, source_src_rect.Location.Y - source_image_rect.Y);
            Rectangle source_test_rect = new Rectangle((source_cropper_rect.X < source_image_rect.X) ? (source_image_rect.X - source_cropper_rect.X) : 0, (source_cropper_rect.Y < source_image_rect.Y) ? (source_image_rect.Y - source_cropper_rect.Y) : 0, source_src_rect.Width, source_src_rect.Height);

            Bitmap bmp = new Bitmap(source_cropper_rect.Width, source_cropper_rect.Height);
            if (source_image_rect.IntersectsWith(source_cropper_rect))
            {
                Graphics g = Graphics.FromImage(bmp);
                GraphicsPath gp = null;
                if (this.CropperShape == ImageCropperCropShape.Circular)
                {
                    gp = new GraphicsPath();
                    gp.AddEllipse(new RectangleF(0, 0, source_cropper_rect.Width, source_cropper_rect.Height));
                    g.SetClip(gp);
                }

                g.DrawImage(source_image, source_test_rect, source_src_rect, GraphicsUnit.Pixel);

                g.Dispose();
                if (gp != null)
                    gp.Dispose();
            }

            return bmp;
        }

        /// <summary>
        /// 获取缩放状态剪切区域Rectangle
        /// </summary>
        /// <returns></returns>
        public Rectangle GetCropperScaleRectangle()
        {
            if (this.image_tmp == null)
                return Rectangle.Empty;

            return new Rectangle(this.cropper_rect.X - this.content_rect.X, this.cropper_rect.Y - this.content_rect.Y, this.cropper_rect.Width, this.cropper_rect.Height);
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 初始化控件内部元素布局
        /// </summary>
        public void InitializeElement()
        {
            this.InitializeContentDefaultRectangle();
            this.UpdateCropperRectangle(this.GetCropperDefaultRectangle());
            this.InitializeImageDefaultRectangle();
        }

        /// <summary>
        /// 初始化内容区默认rect
        /// </summary>
        private void InitializeContentDefaultRectangle()
        {
            int scale_cropperThumbRadius = this.GetCropperThumbRadius();
            this.content_rect = new Rectangle(this.ClientRectangle.X + scale_cropperThumbRadius, this.ClientRectangle.Y + scale_cropperThumbRadius, this.ClientRectangle.Width - scale_cropperThumbRadius * 2, this.ClientRectangle.Height - scale_cropperThumbRadius * 2);
        }

        /// <summary>
        /// 初始化图片区域为默认rect
        /// </summary>
        private void InitializeImageDefaultRectangle()
        {
            if (this.image_tmp != null)
            {
                this.image_rect = new Rectangle(this.ClientRectangle.X + (this.ClientRectangle.Width - this.image_tmp.Width) / 2, this.ClientRectangle.Y + (this.ClientRectangle.Height - this.image_tmp.Height) / 2, this.image_tmp.Width, this.image_tmp.Height);
            }
            else
            {
                this.image_rect = Rectangle.Empty;
            }
        }

        /// <summary>
        /// 更新剪切区rect
        /// </summary>
        /// <param name="_cropper_rect">剪切区rect</param>
        private void UpdateCropperRectangle(Rectangle _cropper_rect)
        {
            if (this.cropper_rect == _cropper_rect)
                return;

            this.cropper_rect = _cropper_rect;
            this.cropper_path.Reset();
            if (this.CropperShape == ImageCropperCropShape.Rectangular)
            {
                this.cropper_path.AddRectangle(this.cropper_rect);
            }
            else
            {
                this.cropper_path.AddEllipse(this.cropper_rect);
            }

            int scale_cropperThumbRadius = this.GetCropperThumbRadius();

            this.cropper_thumbs[ImageCropperDragType.LeftTop] = new Rectangle(this.cropper_rect.X - scale_cropperThumbRadius, this.cropper_rect.Y - scale_cropperThumbRadius, scale_cropperThumbRadius * 2, scale_cropperThumbRadius * 2);
            this.cropper_thumbs[ImageCropperDragType.RightTop] = new Rectangle(this.cropper_rect.Right - scale_cropperThumbRadius, this.cropper_rect.Y - scale_cropperThumbRadius, scale_cropperThumbRadius * 2, scale_cropperThumbRadius * 2);
            this.cropper_thumbs[ImageCropperDragType.RightBottom] = new Rectangle(this.cropper_rect.Right - scale_cropperThumbRadius, this.cropper_rect.Bottom - scale_cropperThumbRadius, scale_cropperThumbRadius * 2, scale_cropperThumbRadius * 2);
            this.cropper_thumbs[ImageCropperDragType.LeftBottom] = new Rectangle(this.cropper_rect.X - scale_cropperThumbRadius, this.cropper_rect.Bottom - scale_cropperThumbRadius, scale_cropperThumbRadius * 2, scale_cropperThumbRadius * 2);

            this.cropper_thumbs[ImageCropperDragType.Top] = new Rectangle(this.cropper_rect.X + (this.cropper_rect.Width / 2) - scale_cropperThumbRadius, this.cropper_rect.Y - scale_cropperThumbRadius, scale_cropperThumbRadius * 2, scale_cropperThumbRadius * 2);
            this.cropper_thumbs[ImageCropperDragType.Right] = new Rectangle(this.cropper_rect.Right - scale_cropperThumbRadius, this.cropper_rect.Y + (this.cropper_rect.Height / 2) - scale_cropperThumbRadius, scale_cropperThumbRadius * 2, scale_cropperThumbRadius * 2);
            this.cropper_thumbs[ImageCropperDragType.Bottom] = new Rectangle(this.cropper_rect.X + (this.cropper_rect.Width / 2) - scale_cropperThumbRadius, this.cropper_rect.Bottom - scale_cropperThumbRadius, scale_cropperThumbRadius * 2, scale_cropperThumbRadius * 2);
            this.cropper_thumbs[ImageCropperDragType.Left] = new Rectangle(this.cropper_rect.X - scale_cropperThumbRadius, this.cropper_rect.Y + (this.cropper_rect.Height / 2) - scale_cropperThumbRadius, scale_cropperThumbRadius * 2, scale_cropperThumbRadius * 2);

            this.OnCropperRectangleChanged(EventArgs.Empty);
        }

        /// <summary>
        /// 获取剪切区拇指半径
        /// </summary>
        /// <returns></returns>
        private int GetCropperThumbRadius()
        {
            return (int)Math.Ceiling(this.ThumbSize * this.ScaleDpi / 2);
        }

        /// <summary>
        /// 获取剪切区默认rect
        /// </summary>
        /// <returns></returns>
        private Rectangle GetCropperDefaultRectangle()
        {
            if (this.CropperShape == ImageCropperCropShape.Rectangular)
            {
                int default_width = this.content_rect.Width * 3 / 10;
                int default_height = this.content_rect.Height * 3 / 10;
                if (this.CropperAspectRatio.HasValue)
                {
                    if (this.CropperAspectRatio >= 1)
                    {
                        default_width = this.content_rect.Width * 3 / 10;
                        default_height = (int)(default_width / this.CropperAspectRatio);
                        if (default_height > this.content_rect.Height * 3 / 10)
                        {
                            default_height = this.content_rect.Height * 3 / 10;
                            default_width = (int)(default_height * this.CropperAspectRatio);
                        }
                    }
                    else
                    {
                        default_height = this.content_rect.Height * 3 / 10;
                        default_width = (int)(default_height * this.CropperAspectRatio);
                        if (default_width > this.content_rect.Width * 3 / 10)
                        {
                            default_width = this.content_rect.Width * 3 / 10;
                            default_height = (int)(default_width / this.CropperAspectRatio);
                        }
                    }
                }

                return new Rectangle(this.content_rect.X + (this.content_rect.Width - default_width) / 2, this.content_rect.Y + (this.content_rect.Height - default_height) / 2, default_width, default_height);
            }
            else
            {
                int minSize = Math.Min(this.content_rect.Width, this.content_rect.Height) / 3;
                return new Rectangle(this.content_rect.X + (this.content_rect.Width - minSize) / 2, this.content_rect.Y + (this.content_rect.Height - minSize) / 2, minSize, minSize);
            }

        }

        /// <summary>
        /// 把缩放rect转换成真实rect
        /// </summary>
        /// <param name="scaleRect">缩放rect</param>
        /// <returns></returns>
        private Rectangle ConvertRectangle(Rectangle scaleRect)
        {
            Rectangle realityRect = new Rectangle((int)(scaleRect.X / this.ImageScaleRatio / 100f), (int)(scaleRect.Y / this.ImageScaleRatio / 100f), (int)(scaleRect.Width / this.ImageScaleRatio / 100f), (int)(scaleRect.Height / this.ImageScaleRatio / 100f));
            if (this.CropperAspectRatio.HasValue)
            {
                realityRect.Height = (int)(realityRect.Width / this.CropperAspectRatio.Value);
            }
            return realityRect;
        }

        /// <summary>
        /// 更新图片缓存
        /// </summary>
        private void UpdateImageTmp()
        {
            Image tmp = this.image_tmp;

            if (this.Image != null)
            {
                this.image_tmp = ControlHelper.ScaleImage(this.Image, new Size((int)(this.Image.Size.Width * this.ImageScaleRatio / 100f), (int)(this.Image.Size.Height * this.ImageScaleRatio / 100f)));
                if (tmp != null)
                    tmp.Dispose();
            }
            else
            {
                if (this.image_tmp != null)
                {
                    this.image_tmp.Dispose();
                    this.image_tmp = null;
                }
            }
        }

        /// <summary>
        /// 更新背景网格图片缓存
        /// </summary>
        private void UpdateGripImageTmp()
        {
            if (this.GripVisible)
            {
                Image tmp = this.gripimage_tmp;

                int scale_gripSize = (int)Math.Ceiling(this.GripSize * this.ScaleDpi);
                Bitmap grip_bmp = new Bitmap(scale_gripSize * 2, scale_gripSize * 2);
                Graphics g = Graphics.FromImage(grip_bmp);

                SolidBrush back_sb = new SolidBrush(Color.White);
                g.FillRectangle(back_sb, this.ClientRectangle);
                back_sb.Color = Color.FromArgb(204, 204, 204);
                g.FillRectangles(back_sb, new RectangleF[] { new RectangleF(0, 0, scale_gripSize, scale_gripSize), new RectangleF(scale_gripSize, scale_gripSize, scale_gripSize, scale_gripSize) });
                back_sb.Dispose();

                this.gripimage_tmp = grip_bmp;
                g.Dispose();

                if (tmp != null)
                    tmp.Dispose();
            }
            else
            {
                this.gripimage_tmp.Dispose();
                this.gripimage_tmp = null;
            }
        }


        #endregion

        #region 外观

        public class StyleAppearanceObject : AppearanceObjectBase
        {
            internal StyleAppearanceObject(ISkinObject owner, AppearanceObjectBase parent) : base(owner, parent) { }

            #region 属性

            private Color skinBackColor = Color.Empty;
            private readonly Color defaultBackColor = SystemColors.Control;
            private Color backColor = Color.Empty;
            /// <summary>
            /// 背景颜色
            /// </summary>
            [Description("背景颜色")]
            [PropertyOrder(-195)]
            [SkinProperty(true, true)]
            public Color BackColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore() && this.skinBackColor != Color.Empty)
                    {
                        return this.skinBackColor;
                    }

                    if (this.backColor != Color.Empty)
                    {
                        return this.backColor;
                    }

                    if (((Control)this.owner).Parent != null)
                    {
                        return ((Control)this.owner).Parent.BackColor;
                    }

                    return this.defaultBackColor;
                }
                set
                {
                    if (this.backColor == value)
                        return;

                    this.backColor = value;
                    this.Invalidate();
                }
            }
            private bool ShouldSerializeBackColor()
            {
                return this.backColor != Color.Empty;
            }
            private void ResetBackColor()
            {
                this.backColor = Color.Empty;
                this.Invalidate();
            }

            private Color skinTextColor = Color.Empty;
            private readonly Color defaultTextColor = SystemColors.ControlText;
            private Color textColor = Color.Empty;
            /// <summary>
            /// 文本颜色
            /// </summary>
            [Description("文本颜色")]
            [PropertyOrder(-193)]
            [SkinProperty(true, true)]
            public Color TextColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore() && this.skinTextColor != Color.Empty)
                    {
                        return this.skinTextColor;
                    }

                    if (this.textColor != Color.Empty)
                    {
                        return this.textColor;
                    }

                    if (((Control)this.owner).Parent != null)
                    {
                        return ((Control)this.owner).Parent.ForeColor;
                    }

                    return this.defaultTextColor;
                }
                set
                {
                    if (this.textColor == value)
                        return;

                    this.textColor = value;
                    this.Invalidate();
                }
            }
            private bool ShouldSerializeTextColor()
            {
                return this.textColor != Color.Empty;
            }
            private void ResetTextColor()
            {
                this.textColor = Color.Empty;
                this.Invalidate();
            }

            private Color skinMaskingColor = Color.Empty;
            private readonly Color defaultMaskingColor = Color.FromArgb(130, 0, 0, 0);
            private Color maskingColor = Color.Empty;
            /// <summary>
            /// 蒙层颜色
            /// </summary>
            [Description("蒙层颜色")]
            [PropertyOrder(-192)]
            [Editor(typeof(AlphaColorEditor), typeof(UITypeEditor))]
            [SkinProperty(true, false)]
            public Color MaskingColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore())
                    {
                        return this.skinMaskingColor;
                    }

                    if (this.maskingColor != Color.Empty)
                    {
                        return this.maskingColor;
                    }

                    return this.defaultMaskingColor;
                }
                set
                {
                    if (this.maskingColor == value)
                        return;

                    this.maskingColor = value;
                    this.Invalidate();
                }
            }
            private bool ShouldSerializeMaskingColor()
            {
                return this.maskingColor != Color.Empty;
            }
            private void ResetMaskingColor()
            {
                this.maskingColor = Color.Empty;
                this.Invalidate();
            }

            private Color skinThumbBorderColor = Color.Empty;
            private readonly Color defaultThumbBorderColor = Color.Gray;
            private Color thumbBorderColor = Color.Empty;
            /// <summary>
            /// 剪切区域拇指边框颜色
            /// </summary>
            [Description("剪切区域拇指边框颜色")]
            [PropertyOrder(-188)]
            [SkinProperty(true, false)]
            public Color ThumbBorderColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore())
                    {
                        return this.skinThumbBorderColor;
                    }

                    if (this.thumbBorderColor != Color.Empty)
                    {
                        return this.thumbBorderColor;
                    }

                    return this.defaultThumbBorderColor;
                }
                set
                {
                    if (this.thumbBorderColor == value)
                        return;

                    this.thumbBorderColor = value;
                    this.Invalidate();
                }
            }
            private bool ShouldSerializeThumbBorderColor()
            {
                return this.thumbBorderColor != Color.Empty;
            }
            private void ResetThumbBorderColor()
            {
                this.thumbBorderColor = Color.Empty;
                this.Invalidate();
            }

            private Color skinThumbBackColor = Color.Empty;
            private readonly Color defaultThumbBackColor = Color.White;
            private Color thumbBackColor = Color.Empty;
            /// <summary>
            /// 剪切区域拇指背景颜色
            /// </summary>
            [Description("剪切区域拇指背景颜色")]
            [PropertyOrder(-186)]
            [SkinProperty(true, false)]
            public Color ThumbBackColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore())
                    {
                        return this.skinThumbBackColor;
                    }

                    if (this.thumbBackColor != Color.Empty)
                    {
                        return this.thumbBackColor;
                    }

                    return this.defaultThumbBackColor;
                }
                set
                {
                    if (this.thumbBackColor == value)
                        return;

                    this.thumbBackColor = value;
                    this.Invalidate();
                }
            }
            private bool ShouldSerializeThumbBackColor()
            {
                return this.thumbBackColor != Color.Empty;
            }
            private void ResetThumbBackColor()
            {
                this.thumbBackColor = Color.Empty;
                this.Invalidate();
            }

            #endregion

        }

        #endregion

    }
}
